package com.gnrsoft.rpc.server;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.gnrsoft.rpc.common.RpcDecoder;
import com.gnrsoft.rpc.common.RpcEncoder;
import com.gnrsoft.rpc.common.RpcResponse;
import com.gnrsoft.rpc.registry.ServiceRegistry;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class RpcServer implements ApplicationContextAware, InitializingBean {

	public RpcServer() {
	}

	public RpcServer(String serverAddress, ServiceRegistry serviceRegistry) {
		this.serverAddress = serverAddress;
		this.serviceRegistry = serviceRegistry;

	}

	private String serverAddress;

	private ServiceRegistry serviceRegistry;
	//key自定义注解RPCService的value   value 自定义注解RPCService的bean
	private Map<String, Object> handlerMap = new HashMap<String, Object>();

	@Override
	public void setApplicationContext(ApplicationContext act) throws BeansException {
		// 拿到 使用 RpcService 注解的类的beanMap
		Map<String, Object> serviceBeanMap = act.getBeansWithAnnotation(RpcService.class);
		if (MapUtils.isNotEmpty(serviceBeanMap)) {
			//迭代bean
			for (Object serviceBean : serviceBeanMap.values()) {
				// 拿到注解的value
				// HelloService
				String interfaceName = serviceBean.getClass().getAnnotation(RpcService.class).value().getName();
				// key HelloService value 实现类
				handlerMap.put(interfaceName, serviceBean);
			}
		}

	}

	/**
	 * 
	 * <B>方法名称：服务启动</B><BR>
	 * <B>概要说明：开始启动服务端，监听端口</B><BR>
	 * 
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	@Override
	public void afterPropertiesSet() throws Exception {

		// boss 接收client连接
		EventLoopGroup parentGroup = new NioEventLoopGroup();
		// worker 业务处理操作
		EventLoopGroup childGroup = new NioEventLoopGroup();

		try {
			// socket 服务端配置
			ServerBootstrap serverBootstrap = new ServerBootstrap();
			serverBootstrap.group(parentGroup, childGroup)
					// 指定 NioServerSocketChannel 非阻塞式IO模型
					// OioServerSocketChannel是传统IO模型，阻塞式IO
					.channel(NioServerSocketChannel.class)
					// 设置发送缓冲大小
					// .childOption(ChannelOption.SO_SNDBUF, 8 * 1024)
					// 设置接收缓冲大小
					// .option(ChannelOption.SO_RCVBUF, 8 * 1024)
					// 设置tcp的缓冲区
					.option(ChannelOption.SO_BACKLOG, 128)
					// 保持连接
					.childOption(ChannelOption.SO_KEEPALIVE, true)
					// 绑定事件处理器，处理客户端逻辑
					.childHandler(new ChannelInitializer<SocketChannel>() {
						@Override
						protected void initChannel(SocketChannel socketChannel) throws Exception {

							socketChannel.pipeline().addLast(new RpcDecoder()); // 解码
							socketChannel.pipeline().addLast(new RpcEncoder(RpcResponse.class)); // 编码

							socketChannel.pipeline().addLast(new RpcHandler(handlerMap));

						}
					});

			// 监听服务地址 ，与端口
			String[] serverAddressArray = serverAddress.split(":");
			ChannelFuture cf = serverBootstrap.bind(serverAddressArray[0], Integer.parseInt(serverAddressArray[1]))
					.sync(); // 绑定

			System.out.println("Server begin...... ip = " + serverAddressArray[0] + " port = " + serverAddressArray[1]);

			//zookeeper 中注册服务
			if (null != serviceRegistry) {
				serviceRegistry.registry(serverAddress);
			}

			cf.channel().closeFuture().sync(); // 等待关闭

		} finally {
			parentGroup.shutdownGracefully();
			childGroup.shutdownGracefully();
		}

	}

	public String getServerAddress() {
		return serverAddress;
	}

	public void setServerAddress(String serverAddress) {
		this.serverAddress = serverAddress;
	}

	public ServiceRegistry getServiceRegistry() {
		return serviceRegistry;
	}

	public void setServiceRegistry(ServiceRegistry serviceRegistry) {
		this.serviceRegistry = serviceRegistry;
	}

	// public Map<String, Object> getHandlerMap() {
	// return handlerMap;
	// }
	//
	// public void setHandlerMap(Map<String, Object> handlerMap) {
	// this.handlerMap = handlerMap;
	// }

}
